package zdream.control.foe.mm2shot;

import zdream.control.world.MFoe;
import zdream.control.world.LevelWorld;
import zdream.control.world.Ticker;
import zdream.control.world.buff.JumpModule;
import zdream.control.world.buff.StageModule;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>2 代冰关那个会发抛物线子弹的圆形怪
 * <p>
 * <li>不移动, 但不是固定的怪
 * <li>这里改成: 无碰撞伤害, 但是有敌人在面前时就不停地糊脸.
 * <li>HP:5 (1280), 碰撞伤害:无
 * <li>侦测: 敌人到达面前, 高为3 长为5 的方形区域, 从普通模式转为激活模式,
 * 攻击频率都加快, 子弹速率可调.
 * <li>普通模式子弹只有一种 (圆白弹), 伤害 2.
 * 按照近 8 子弹、远 8 子弹交替运行.
 * <li>激活模式子弹有两种, 圆白弹伤害 2, 另一种分情况, (TODO 暂时不做)
 * 如果 shotman 是蓝色, 发冰弹, 伤害 1, 会触发冰冻 BUFF;
 * 如果 shotman 是红色, 发火弹, 伤害 1, 会触发点燃 BUFF;
 * </li></p>
 *
 * @author Zdream
 * @since 0.0.1
 * @date 2020-06-11 (created)
 * @date 2022-06-05 (last modified)
 */
public class MM2ShotMan extends MFoe {
	public static final String NAME = "MM2ShotMan";

	@Override
	public String foeName() {
		return NAME;
	}

	public MM2ShotMan(LevelWorld world) {
		super(world);
		setTerrainWithAllSides(BOX_TERRAIN_SOFT_SOLID);
	}

	@Override
	public void init() {
		buildHealthModule()
				.hpMax(5)
				.create();

		buildStageModule()
				.defineInitStage(STAGE_START, this::tickMotion)
				.defineStage(STAGE_TO_UP, this::tickMotion)
				.defineStage(STAGE_TO_DOWN, this::tickMotion)
				.create();
	}

	@Override
	public boolean is(String category) {
		if (super.is(category)) {
			return true;
		}
		if ("speciesA".equals(category)) {
			return species == 0;
		}
		if ("speciesB".equals(category)) {
			return species == 1;
		}
		return false;
	}

	/**
	 * 0 - 红色种
	 * 1 - 蓝色种
	 */
	byte species;

	/**
	 * 行为: 是否自动搜寻敌人, 敌人在面前就火力全开
	 */
	boolean findEnemy;

	/* **********
	 *  motion  *
	 ********** */

	public static final String STAGE_START = "start";
	public static final String STAGE_TO_UP = "toUp";
	public static final String STAGE_TO_DOWN = "toDown";

	private void tickMotion(StageModule s, Ticker ticker) {
		velocityX = velocityY = 0;

		// 计算是否被激活
		MFoe enemy = null;
		if (findEnemy) {
			enemy = findEnemy();
		}

		if (enemy != null) {
			// 激活
			if (high) {
				changePosture(s);
			} else {
				// 0.5 秒发子弹
				long duration = age - lastAttackAge;
				if (duration >= 500) {
					shotEnemy(enemy);
					resetAttackState();
				}
			}
		} else {
			long duration = age - lastAttackAge;
			if (attackCount >= 8) {
				if (duration >= 400) {
					changePosture(s);
				}
			}

			if (attackCount != 0 && duration >= 1000 || attackCount == 0 && duration >= 1500) {
				shot();
				resetAttackState();
			}
		}
	}

	/* **********
	 * 行为参数 *
	 ********** */

	/**
	 * 上次攻击时的 age. 普通模式;
	 * 普通模式每过 1 秒就发一颗子弹,
	 * 激活模式每过 0.5 秒就发一颗子弹.
	 */
	long lastAttackAge;
	/**
	 * 当前
	 */
	int attackCount;
	/**
	 * 是否在高射炮状态
	 */
	boolean high;
	private final List<MFoe> tmpFoeArray = new ArrayList<>();

	private MFoe findEnemy() {
		float cx = getCenterX(), cy = getCenterY();
		float px = (orientation) ? pos.x + pos.width + 0.2f : pos.x - 6;

		tmpFoeArray.clear();
		world.findOverlapFoeAndPutInList(tmpFoeArray, px, getCenterY() - 1.5f, 5, 3);
		MFoe nearestEnemy = null;
		float distance = 0;

		for (MFoe enemy : tmpFoeArray) {
			if (enemy.side == side) {
				continue;
			}

			switch (type) {
				case TYPE_LEADER: case TYPE_FOE: case TYPE_ELITE:
					float ex = getCenterX(), ey = getCenterY();
					float d = Math.abs(ex - cx) + Math.abs(ey - cy);
					if (nearestEnemy == null || d <= distance) {
						nearestEnemy = enemy;
						distance = d;
					}
					break;
			}
		}

		return nearestEnemy;
	}

	private void changePosture(StageModule s) {
		high = !high;

		if (high) {
			s.changeStageTo(STAGE_TO_UP);
		} else {
			s.changeStageTo(STAGE_TO_DOWN);
		}

		attackCount = 0;
		lastAttackAge = age;
	}

	private void shot() {
		int n = (orientation ? 1 : 0) + (high ? 2 : 0);
		MM2ShotManBullet bullet = new MM2ShotManBullet(this);

		float bulletX, bulletY, vx, initVy, maxVy = 28;

		switch (n) {
			case 0: // 左、低炮
				bulletX = anchorX - 0.9f;
				bulletY = anchorY + 0.8f;
				vx = -16;
				initVy = 4;
				break;
			case 1: // 右、低炮
				bulletX = anchorX + 0.9f;
				bulletY = anchorY + 0.8f;
				vx = 16;
				initVy = 4;
				break;
			case 2: // 左、高炮
				bulletX = anchorX - 0.7f;
				bulletY = anchorY + 1.5f;
				vx = -8;
				initVy = 16;
				break;
			case 3: // 右、高炮
				bulletX = anchorX + 0.7f;
				bulletY = anchorY + 1.5f;
				vx = 8;
				initVy = 16;
				break;

			default:
				return; // 不可能到这里
		}

		bullet.set(vx, initVy, JumpModule.GRAVITY_ACCELERATION, maxVy);
		world.createFoe(bullet, bulletX, bulletY, orientation);

		this.attackCount++;
	}

	private void shotEnemy(MFoe enemy) {
		// 喷口位置
		float srcPx = (orientation) ? anchorX + 0.9f : anchorX - 0.9f;
		float srcPy = anchorY + 0.8f;

		// 对方位置
		float destPx = enemy.getCenterX();
		float destPy = enemy.getCenterY();

		// 双方的水平距离, 非负数
		float pDeltaX = Math.abs(destPx - srcPx); // 非负数
		float vx = 16; // 正数
		float time = pDeltaX / vx; // 非负数

		if (pDeltaX == 0 || time == 0 ||
				orientation && destPx < srcPx || !orientation && destPx > srcPx) {
			shot();
			return;
		}

		float ay = -JumpModule.GRAVITY_ACCELERATION;
		float dropY = (time - 1) * time * ay / 2; // 负数
		float vy = (destPy - dropY - srcPy) / time;
		if (vy < 0) {
			vy = 0;
		}
		if (vy > vx / 2) {
			vy = vx / 2;
		}

		MM2ShotManBullet bullet = new MM2ShotManBullet(this);

		bullet.set(orientation ? vx : -vx, vy, ay, 28);
		world.createFoe(bullet, srcPx, srcPy, orientation);

		this.attackCount++;
	}

	private void resetAttackState() {
		this.lastAttackAge = age;
	}
}
